package com.wlb365.financing.modules.esign.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Maps;
import com.wlb365.financing.common.constants.ApiConstants;
import com.wlb365.financing.common.constants.SysConstant;
import com.wlb365.financing.common.exception.AdminException;
import com.wlb365.financing.common.utils.ShiroUtil;
import com.wlb365.financing.common.utils.StringUtils;
import com.wlb365.financing.modules.esign.request.CancelOrgAcctReq;
import com.wlb365.financing.modules.esign.request.CancelPersonAcctReq;
import com.wlb365.financing.modules.esign.request.CreateFileByTemplateReq;
import com.wlb365.financing.modules.esign.request.CreateOrgAcctReq;
import com.wlb365.financing.modules.esign.request.CreateOrgDto;
import com.wlb365.financing.modules.esign.request.CreatePersonAcctReq;
import com.wlb365.financing.modules.esign.request.CreatePersonDto;
import com.wlb365.financing.modules.esign.request.CreateSignFlowReq;
import com.wlb365.financing.modules.esign.request.DownFlowDocReq;
import com.wlb365.financing.modules.esign.request.EsignQueryPageReq;
import com.wlb365.financing.modules.esign.request.QueryFlowSignersReq;
import com.wlb365.financing.modules.esign.request.QueryOrgAcctReq;
import com.wlb365.financing.modules.esign.request.QueryPersonAcctReq;
import com.wlb365.financing.modules.esign.request.QuerySignAntPushInfoReq;
import com.wlb365.financing.modules.esign.request.QuerySignFlowReq;
import com.wlb365.financing.modules.esign.request.QuerySignFlowUrlReq;
import com.wlb365.financing.modules.esign.response.CreateFileByTemplateRes;
import com.wlb365.financing.modules.esign.response.CreateOrgAcctRes;
import com.wlb365.financing.modules.esign.response.CreatePersonAcctRes;
import com.wlb365.financing.modules.esign.response.CreateSignFlowRes;
import com.wlb365.financing.modules.esign.response.DownFlowDocRes;
import com.wlb365.financing.modules.esign.response.EsignQueryPageRes;
import com.wlb365.financing.modules.esign.response.FlowSignerDto;
import com.wlb365.financing.modules.esign.response.QueryFlowSignersRes;
import com.wlb365.financing.modules.esign.response.QueryOrgAcctRes;
import com.wlb365.financing.modules.esign.response.QueryPersonAcctRes;
import com.wlb365.financing.modules.esign.response.QuerySignAntPushInfoRes;
import com.wlb365.financing.modules.esign.response.QuerySignFlowRes;
import com.wlb365.financing.modules.esign.response.QuerySignFlowUrlRes;
import com.wlb365.financing.modules.esign.vo.EsignQueryVO;
import com.wlb365.financing.modules.sys.entity.Dept;
import com.wlb365.financing.modules.sys.entity.User;
import com.wlb365.financing.modules.sys.mapper.DeptMapper;
import com.wlb365.financing.modules.sys.mapper.UserMapper;
import com.wlb365.financing.modules.trade.response.VoucherDetailRes;
import com.wlb365.financing.modules.trade.service.IVoucherService;
import com.wlb365.financing.common.utils.SdkHelper;
import com.wlb365.sdk.model.CommonResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 概述：
 * </p>
 *
 * @author zwh
 * @version 1.0
 * @copyRight 北京微利宝信息技术有限公司  All right reserved.
 * @date 2021/4/20
 */
@Service
public class ESignService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private DeptMapper deptMapper;
    @Autowired
    private IVoucherService voucherService;

    public CreatePersonAcctRes createPersonAcct (CreatePersonDto dto) {
        User user = userMapper.selectById(dto.getId());
        if (StringUtils.isNotEmpty(user.getAccountId())) {
            throw new AdminException("用户已开通签名账号");
        }
        dto.setThirdPartyUserId(IdUtil.simpleUUID());
        if (StringUtils.isEmpty(dto.getIdType())) {
            dto.setIdType("CRED_PSN_CH_IDCARD");
        }
        CreatePersonAcctReq req = new CreatePersonAcctReq();
        req.setBizModel(dto);
        CreatePersonAcctRes res = SdkHelper.execute(req);
        if (ApiConstants.SUCCESS_CODE.equals(res.getCode())) {
            user.setId(dto.getId());
            user.setThirdPartyUserId(dto.getThirdPartyUserId());
            user.setAccountId(res.getAccountId());
            userMapper.updateById(user);
        } else {
            throw new AdminException("创建个人签名账号失败：" + res.getMsg() + res.getSubMsg());
        }
        return res;
    }

    public void cancelPersonAcct (String id) {
        User user = userMapper.selectById(id);
        if (StringUtils.isEmpty(user.getAccountId())) {
            throw new AdminException("用户未开通签名账号");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("accountId", user.getAccountId());
        CancelPersonAcctReq req = new CancelPersonAcctReq();
        req.setBizModel(params);
        CommonResponse res = SdkHelper.execute(req);
        if (ApiConstants.SUCCESS_CODE.equals(res.getCode())) {
            user.setAccountId("");
            user.setUpdateTime(new Date());
            userMapper.updateById(user);
            if (ShiroUtil.getUserId().equals(user.getId())) {
                //如果注销当前登录用户账号，手动清除shiro中账号信息
                ShiroUtil.getUser().setAccountId("");
            }
        } else {
            throw new AdminException("注销个人签名账号失败：" + res.getMsg() + res.getSubMsg());
        }
    }

    public QueryPersonAcctRes queryPersonAcct (String id) {
        User user = userMapper.selectById(id);
        if (StringUtils.isEmpty(user.getAccountId())) {
            throw new AdminException("用户未开通签名账号");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("accountId", user.getAccountId());
        QueryPersonAcctReq req = new QueryPersonAcctReq();
        req.setBizModel(params);
        QueryPersonAcctRes res = SdkHelper.execute(req);
        if (ApiConstants.SUCCESS_CODE.equals(res.getCode())) {
            return res;
        } else {
            throw new AdminException("查看个人签名账号失败：" + res.getMsg() + res.getSubMsg());
        }
    }

    public CreateOrgAcctRes createOrgAcct (CreateOrgDto dto) {
        Dept dept = deptMapper.selectById(dto.getId());
        if (StringUtils.isNotEmpty(dept.getAccountId())) {
            throw new AdminException("机构已开通签名账号");
        }
        User user = ShiroUtil.getUser();
        if (StringUtils.isEmpty(user.getAccountId())) {
            throw new AdminException("您还未创建个人签章账号");
        }
        if (!user.getDeptId().equals(dept.getId())){
            throw new AdminException("非当前机构登录用户，不能创建机构账号");
        }
        dto.setCreator(user.getAccountId());
        dto.setThirdPartyUserId(IdUtil.simpleUUID());
        dto.setCreator(user.getAccountId());
        if (StringUtils.isEmpty(dto.getIdType())) {
            dto.setIdType("CRED_ORG_USCC");
        }
        CreateOrgAcctReq req = new CreateOrgAcctReq();
        req.setBizModel(dto);
        CreateOrgAcctRes res = SdkHelper.execute(req);
        if (ApiConstants.SUCCESS_CODE.equals(res.getCode())) {
            dept.setId(dto.getId());
            dept.setThirdPartyUserId(dto.getThirdPartyUserId());
            dept.setAccountId(res.getOrgId());
            dept.setIdNumber(dto.getIdNumber());
            dept.setOrgLegalIdNumber(dto.getOrgLegalIdNumber());
            dept.setOrgLegalName(dto.getOrgLegalName());
            dept.setCreator(dto.getCreator());
            deptMapper.updateById(dept);
        } else {
            throw new AdminException("创建机构签名账号失败：" + res.getMsg() + res.getSubMsg());
        }
        return res;
    }

    public void cancelOrgAcct (String id) {
        Dept dept = deptMapper.selectById(id);
        if (StringUtils.isEmpty(dept.getAccountId())) {
            throw new AdminException("机构未开通签名账号");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("orgId", dept.getAccountId());
        CancelOrgAcctReq req = new CancelOrgAcctReq();
        req.setBizModel(params);
        CommonResponse res = SdkHelper.execute(req);
        if (ApiConstants.SUCCESS_CODE.equals(res.getCode())) {
            dept.setAccountId("");
            dept.setUpdateTime(new Date());
            deptMapper.updateById(dept);
        } else {
            throw new AdminException("注销机构签名账号失败：" + res.getMsg() + res.getSubMsg());
        }
    }

    public QueryOrgAcctRes querOrgAcct (String id) {
        Dept dept = deptMapper.selectById(id);
        if (StringUtils.isEmpty(dept.getAccountId())) {
            throw new AdminException("机构未开通签名账号");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("orgId", dept.getAccountId());
        QueryOrgAcctReq req = new QueryOrgAcctReq();
        req.setBizModel(params);
        QueryOrgAcctRes res = SdkHelper.execute(req);
        if (ApiConstants.SUCCESS_CODE.equals(res.getCode())) {
            if (StringUtils.isNotEmpty(res.getCreator())) {
                //机构签章创建人可能为空（个人账号注销了，就是空的了）
                LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                lambdaQueryWrapper.eq(User::getAccountId, res.getCreator());
                User user = userMapper.selectOne(lambdaQueryWrapper);
                res.setCreatorName(user.getRealname());
            }

           return res;
        } else {
            throw new AdminException("注销机构签名账号失败：" + res.getMsg() + res.getSubMsg());
        }
    }

    public CreateSignFlowRes createSignFlow (String id) {
        //查询凭证详情
        VoucherDetailRes voucherDetail = voucherService.detail(id);
        //查找供应商
        Dept supplier = deptMapper.selectById(voucherDetail.getSupplierId());
        if (supplier == null || StringUtils.isEmpty(supplier.getAccountId())) {
            throw new AdminException("供应商未注册机构签章账号");
        }
        //查找核心企业
        Dept coreEnterprise = deptMapper.selectById(voucherDetail.getCoreEnterpriseId());
        if (coreEnterprise == null || StringUtils.isEmpty(coreEnterprise.getAccountId())) {
            throw new AdminException("核心企业未注册机构签章账号");
        }

        //查询供应商用户
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getDeptId, supplier.getId());
        queryWrapper.isNotNull(User::getAccountId);
        User supplierUser = userMapper.selectOne(queryWrapper);
        if (supplierUser == null || StringUtils.isEmpty(supplierUser.getAccountId())) {
            throw new AdminException("供应商管理员未注册签章账号");
        }

        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getDeptId, coreEnterprise.getId());
        queryWrapper.isNotNull(User::getAccountId);
        User coreEnterpriseUser = userMapper.selectOne(queryWrapper);
        if (supplierUser == null || StringUtils.isEmpty(coreEnterprise.getAccountId())) {
            throw new AdminException("核心企业管理员未注册签章账号");
        }
        //生成签章文件，并填充数据
        Map<String, Object> params = new HashMap<>();
        params.put("templateId", ApiConstants.TEMPLATE_VOUCHER_SIGN_ID);
        //填充的参数
        Map<String, Object> param = new HashMap<>();
        param.put("jiafang", coreEnterprise.getName());
        param.put("yifang", supplier.getName());
        params.put("param", param);

        CreateFileByTemplateRes file = SdkHelper.execute(new CreateFileByTemplateReq(), params);
        if (!ApiConstants.SUCCESS_CODE.equals(file.getCode())) {
            throw new AdminException("开启签章流程失败，请稍后重试");
        }

        //创建签章流程，并设置签章人
        Map<String, Object> signParams = new HashMap<>();
        signParams.put("fileId", file.getFileId());
        signParams.put("businessScene", voucherDetail.getContractNo()+"凭证");
        //签署人列表
        List<Map<String, Object>> signfields = new ArrayList<>();
        Map<String, Object> sign1 = new HashMap<>();
        sign1.put("signerAccountId", supplierUser.getAccountId());
        sign1.put("order", 1);
        Map<String, Object> pos1 = new HashMap<>();
        pos1.put("posPage", 2);
        pos1.put("posX", 160f);
        pos1.put("posY", 680f);
        sign1.put("posBean", pos1);

        Map<String, Object> sign2 = new HashMap<>();
        sign2.put("signerAccountId", coreEnterpriseUser.getAccountId());
        sign2.put("order", 2);
        Map<String, Object> pos2 = new HashMap<>();
        pos2.put("posPage", 2);
        pos2.put("posX", 160f);
        pos2.put("posY", 560f);
        sign2.put("posBean", pos2);

        signfields.add(sign1);
        signfields.add(sign2);
        signParams.put("signfields", signfields);
        CreateSignFlowRes signFlowRes = SdkHelper.execute(new CreateSignFlowReq(), signParams);
        if (!ApiConstants.SUCCESS_CODE.equals(signFlowRes.getCode())) {
            throw new AdminException("开启签署流程失败，请稍后重试");
        }

        //更新凭证签章信息
        voucherService.updateSign(id, signFlowRes.getFlowId());
        return signFlowRes;
    }

    public QuerySignFlowRes getSingFlow(String signFlowId) {
        //查询凭证详情
        Map<String,Object> params = Maps.newHashMap();
        params.put("flowId", signFlowId);
        return SdkHelper.execute(new QuerySignFlowReq(), params);
    }

    /**
    * 获取签署人地址.
    * @param signFlowId
     * @param orgId 机构id
    * @author zwh
    * @return com.wlb365.financing.modules.esign.response.QuerySignFlowRes
    **/
    public QuerySignFlowUrlRes getSingFlowUrl(String signFlowId, String orgId) {
        //查找企业
        Dept org = deptMapper.selectById(orgId);
        if (org == null || StringUtils.isEmpty(org.getAccountId())) {
            throw new AdminException("机构未注册机构签章账号");
        }

        //查询机构签章用户
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getDeptId, org.getId());
        queryWrapper.isNotNull(User::getAccountId);
        User signUser = userMapper.selectOne(queryWrapper);
        if (signUser == null || StringUtils.isEmpty(signUser.getAccountId())) {
            throw new AdminException("机构未注册签章账号");
        }
        //查询凭证详情
        Map<String,Object> params = Maps.newHashMap();
        params.put("flowId", signFlowId);
        params.put("accountId", signUser.getAccountId());
        QuerySignFlowUrlRes res = SdkHelper.execute(new QuerySignFlowUrlReq(), params);
        if (!ApiConstants.SUCCESS_CODE.equals(res.getCode())) {
            throw new AdminException("获取签章流程失败：" + res.getMsg() + "," + res.getSubMsg());
        }
        return res;
    }

    /**
    * 分页查询签章列表.
    * @param queryVO 条件
    * @author zwh
    * @return com.wlb365.financing.modules.esign.response.EsignQueryPageRes
    **/
    public EsignQueryPageRes page(EsignQueryVO queryVO) {
        Map<String, Object> params = Maps.newHashMap();
        params.put("current", queryVO.getCurrent());
        params.put("size", queryVO.getSize());
        if (StringUtils.isNotEmpty(queryVO.getFlowId())) {
            params.put("flowId", queryVO.getFlowId());
        }
        return SdkHelper.execute(new EsignQueryPageReq(), params);
    }

    /***
    * 签署人列表.
    * @param flowId
    * @author zwh
    * @return com.wlb365.financing.modules.esign.response.QueryFlowSignersRes
    **/
    public QueryFlowSignersRes signersList (String flowId) {
        Map<String, Object> params = Maps.newHashMap();
        params.put("flowId", flowId);
        return SdkHelper.execute(new QueryFlowSignersReq(), params);
    }

    /**
    * 查询签署流程上链信息.
    * @param flowId
    * @author zwh
    * @return com.wlb365.financing.modules.esign.response.QuerySignAntPushInfoRes
    **/
    public QuerySignAntPushInfoRes querySignAntPushInfo (String flowId) {
        Map<String, Object> params = Maps.newHashMap();
        params.put("flowId", flowId);
        return SdkHelper.execute(new QuerySignAntPushInfoReq(), params);
    }

    /**
     * 下载流程文档.
     * @param flowId 流程id
     * @author zwh
     * @return com.wlb365.financing.modules.esign.response.QuerySignAntPushInfoRes
     **/
    public DownFlowDocRes downFlowDoc (String flowId) {
        Map<String, Object> params = Maps.newHashMap();
        params.put("flowId", flowId);
        return SdkHelper.execute(new DownFlowDocReq(), params);
    }

    /**
    * 获得当前签署人签署状态.
    * @param flowId 流程id
    * @param accountId 签署人账号id
    * @author zwh
    * @return java.lang.Integer
    **/
    public Integer getSignStatus (String flowId, String accountId){
        if (StringUtils.isEmpty(accountId)) {
            throw new AdminException("流程签署人才能进行确认");
        }
        Map<String, Object> p = Maps.newHashMap();
        p.put("flowId", flowId);
        QueryFlowSignersRes signers = SdkHelper.execute(new QueryFlowSignersReq(), p);
        for (FlowSignerDto signer : signers.getSigners()){
            if (accountId.equals(signer.getSignerAccountId())) {
                return signer.getSignStatus();
            }
        }
        return null;
    }
}
